package drds.server.route.shard_algorithm;

/**
 * 跳增一致性哈希分片 思想源自Google公开论文，比传统一致性哈希更省资源速度更快数据迁移量更少
 * 
 */
public final class ByJumpConsistentHash extends AbstractShardAlgorithm implements ShardAlgorithm {

	private static final long UNSIGNED_MASK = 0x7fffffffffffffffL;
	private static final long JUMP = 1L << 31;
	// If JDK >= 1.8, just use Long.parseUnsignedLong("2862933555777941757")
	// instead.
	private static final long CONSTANT = Long.parseLong("286293355577794175", 10) * 10 + 7;

	private int totalBuckets;

	@Override
	public Integer calculate(String columnValue) {
		return jumpConsistentHash(columnValue.hashCode(), totalBuckets);
	}

	@Override
	public int getShardNum() {
		int nPartition = this.totalBuckets;
		return nPartition;
	}

	public static int jumpConsistentHash(final long key, final int buckets) {
		checkBuckets(buckets);
		long k = key;
		long b = -1;
		long j = 0;

		while (j < buckets) {
			b = j;
			k = k * CONSTANT + 1L;

			j = (long) ((b + 1L) * (JUMP / toDouble((k >>> 33) + 1L)));
		}
		return (int) b;
	}

	private static void checkBuckets(final int buckets) {
		if (buckets < 0) {
			throw new IllegalArgumentException("Buckets cannot be less than 0");
		}
	}

	private static double toDouble(final long n) {
		double d = n & UNSIGNED_MASK;
		if (n < 0) {
			d += 0x1.0p63;
		}
		return d;
	}

	public void setTotalBuckets(int totalBuckets) {
		this.totalBuckets = totalBuckets;
	}

	public int getTotalBuckets() {
		return totalBuckets;
	}
}
